#ifndef vr_common_h
#define vr_common_h
#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>
#include <sstream>
#include <time.h>
#include <math.h>
#define PI 3.141592657

namespace vision_ruler {

    class simple_logger {
        public:
            enum logger_Level {
                info_level=0,
                debug_level=1
            };

            logger_Level loggerLevel=info_level;

            std::string getTime() {
                time_t timestamp;
                time(&timestamp);
                char tmp[32]; 
                strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", localtime(&timestamp));
                return tmp;
            }

            template<typename T, typename ...OtherTypes> 
            void info(const T& __arg, const OtherTypes&... __args) {
                if(logger_Level::info_level <= loggerLevel) {
                    printf("[INFO][%s]: ", getTime().c_str());
                    printf(__arg, __args...); 
                    std::cout<< "" << std::endl;
                }
            }

            template<typename T, typename ...OtherTypes> 
            void debug(const T& __arg, const OtherTypes&... __args) {
                if(logger_Level::debug_level <= loggerLevel) {
                    printf("[DEBUG][%s]: ", getTime().c_str());
                    printf(__arg, __args...); 
                    std::cout<< "" << std::endl;
                }
            }

            void set_logger_Level(logger_Level _lev) {
                loggerLevel = _lev;
            }
 
            static simple_logger * getInstance() {
                static simple_logger instance;
                return &instance;
            }

        private:
            simple_logger() {}            
        
    };

    struct camera_info {
        double k1, k2, k3, p1, p2;
        double cx, cy, fx, fy;
        int width, height;
    };

    struct head_info {
        double width, height;
    };

    struct global_info {
        bool withGps; // true or false, when false, skip the gps calculation
        double latitude; // gps lat
        double longitude; // gps lon
        double altitude; // gps alt
        double pose_yaw; // gps direction -- yaw
        double pose_pitch; // gps direction -- pitch
        double camera_gps_degree; // from gps to camera, while camera is right to gps, the value is positive 
        double lidar_gps_degree;// from gps to lidar, while lidar is right to gps, the value is positive
        global_info(): pose_yaw(0), pose_pitch(0), camera_gps_degree(0), lidar_gps_degree(0), withGps(false) {};
    };

    struct box_info {
        cv::Point2f left_top_pixel; // box pixel coordinate
        cv::Point2f right_bottom_pixel; // box pixel coordinate
        cv::Point3f left_top_coordinate; // box pixel coordinate
        cv::Point3f left_bottom_coordinate; // box pixel coordinate
        cv::Point3f right_top_coordinate; // box pixel coordinate
        cv::Point3f right_bottom_coordinate; // box pixel coordinate
        int comefrom;// data come from 0 camera 1 lidar
        double lidar_estimate_distance;// estimate distance by lidar
        int boxId; // box indices
        double x; // pnp estimate coordinate - x - use for camera 
        double y; // pnp estimate coordinate - y - use for camera 
        double distance; // pnp estimate coordinate - z - use for camera 
        double yaw; // in camera, the yaw between target obj and camera 
        bool isValid; // judge the box is valid, while the pixel coordinate is unexcepted after correction 
        double widthScale, heightScale; 
        double latitude; // target obj lat
        double longitude; // target obj lon
        double altitude; // target obj alt
        box_info(): isValid(true), widthScale(1.0), heightScale(1.0) {};
    };
}

#endif
